package l2p.util;

import java.text.DecimalFormatSymbols;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Vector;

public class PrintfFormat
{
	public static final PrintfFormat LOG_BOSS_KILLED = new PrintfFormat("%s: %s[%d] killed by %s at Loc(%d %d %d) in %s");
	public static final PrintfFormat LOG_BOSS_RESPAWN = new PrintfFormat("%s: %s[%d] scheduled for respawn in %s at %s");

	public PrintfFormat(String fmtArg) throws IllegalArgumentException
	{
		this(Locale.getDefault(), fmtArg);
	}

	/**
	 * Constructs an array of control specifications possibly preceded, separated, or followed by ordinary strings. Control strings begin with unpaired percent
	 * signs. A pair of successive percent signs designates a single percent sign in the format.
	 * 
	 * @param fmtArg Control string.
	 * @exception IllegalArgumentException if the control string is null, zero length, or otherwise malformed.
	 */
	public PrintfFormat(Locale locale, String fmtArg) throws IllegalArgumentException
	{
		dfs = new DecimalFormatSymbols(locale);
		int ePos = 0;
		ConversionSpecification sFmt = null;
		String unCS = nonControl(fmtArg, 0);
		if(unCS != null)
		{
			sFmt = new ConversionSpecification();
			sFmt.setLiteral(unCS);
			vFmt.addElement(sFmt);
		}
		while(cPos != -1 && cPos < fmtArg.length())
		{
			for(ePos = cPos + 1; ePos < fmtArg.length(); ePos++)
			{
				char c = 0;
				c = fmtArg.charAt(ePos);
				if(c == 'i')
					break;
				if(c == 'd')
					break;
				if(c == 'f')
					break;
				if(c == 'g')
					break;
				if(c == 'G')
					break;
				if(c == 'o')
					break;
				if(c == 'x')
					break;
				if(c == 'X')
					break;
				if(c == 'e')
					break;
				if(c == 'E')
					break;
				if(c == 'c')
					break;
				if(c == 's')
					break;
				if(c == '%')
					break;
			}
			ePos = Math.min(ePos + 1, fmtArg.length());
			sFmt = new ConversionSpecification(fmtArg.substring(cPos, ePos));
			vFmt.addElement(sFmt);
			unCS = nonControl(fmtArg, ePos);
			if(unCS != null)
			{
				sFmt = new ConversionSpecification();
				sFmt.setLiteral(unCS);
				vFmt.addElement(sFmt);
			}
		}
	}

	/**
	 * Return a substring starting at <code>start</code> and ending at either the end of the String <code>s</code>, the next unpaired percent sign, or at the
	 * end of the String if the last character is a percent sign.
	 * 
	 * @param s Control string.
	 * @param start Position in the string <code>s</code> to begin looking for the start of a control string.
	 * @return the substring from the start position to the beginning of the control string.
	 */
	private String nonControl(String s, int start)
	{
		cPos = s.indexOf("%", start);
		if(cPos == -1)
			cPos = s.length();
		return s.substring(start, cPos);
	}

	/**
	 * Format an array of objects. Byte, Short, Integer, Long, Float, Double, and Character arguments are treated as wrappers for primitive types.
	 * 
	 * @param o The array of objects to format.
	 * @return The formatted String.
	 */
	public String sprintf(Object[] o)
	{
		Enumeration<?> e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		int i = 0;
		StringBuffer sb = new StringBuffer();
		while(e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if(c == '\0')
				sb.append(cs.getLiteral());
			else if(c == '%')
				sb.append("%");
			else
			{
				if(cs.isPositionalSpecification())
				{
					i = cs.getArgumentPosition() - 1;
					if(cs.isPositionalFieldWidth())
					{
						int ifw = cs.getArgumentPositionForFieldWidth() - 1;
						cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue());
					}
					if(cs.isPositionalPrecision())
					{
						int ipr = cs.getArgumentPositionForPrecision() - 1;
						cs.setPrecisionWithArg(((Integer) o[ipr]).intValue());
					}
				}
				else
				{
					if(cs.isVariableFieldWidth())
					{
						cs.setFieldWidthWithArg(((Integer) o[i]).intValue());
						i++;
					}
					if(cs.isVariablePrecision())
					{
						cs.setPrecisionWithArg(((Integer) o[i]).intValue());
						i++;
					}
				}
				if(o[i] instanceof Byte)
					sb.append(cs.internalsprintf(((Byte) o[i]).byteValue()));
				else if(o[i] instanceof Short)
					sb.append(cs.internalsprintf(((Short) o[i]).shortValue()));
				else if(o[i] instanceof Integer)
					sb.append(cs.internalsprintf(((Integer) o[i]).intValue()));
				else if(o[i] instanceof Long)
					sb.append(cs.internalsprintf(((Long) o[i]).longValue()));
				else if(o[i] instanceof Float)
					sb.append(cs.internalsprintf(((Float) o[i]).floatValue()));
				else if(o[i] instanceof Double)
					sb.append(cs.internalsprintf(((Double) o[i]).doubleValue()));
				else if(o[i] instanceof Character)
					sb.append(cs.internalsprintf(((Character) o[i]).charValue()));
				else if(o[i] instanceof String)
					sb.append(cs.internalsprintf((String) o[i]));
				else
					sb.append(cs.internalsprintf(o[i]));
				if(!cs.isPositionalSpecification())
					i++;
			}
		}
		return sb.toString();
	}

	/**
	 * Format nothing. Just use the control string.
	 * 
	 * @return the formatted String.
	 */
	public String sprintf()
	{
		Enumeration<?> e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while(e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if(c == '\0')
				sb.append(cs.getLiteral());
			else if(c == '%')
				sb.append("%");
		}
		return sb.toString();
	}

	/**
	 * Format an int.
	 * 
	 * @param x The int to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException if the conversion character is f, e, E, g, G, s, or S.
	 */
	public String sprintf(int x) throws IllegalArgumentException
	{
		Enumeration<?> e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while(e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if(c == '\0')
				sb.append(cs.getLiteral());
			else if(c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format an long.
	 * 
	 * @param x The long to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException if the conversion character is f, e, E, g, G, s, or S.
	 */
	public String sprintf(long x) throws IllegalArgumentException
	{
		Enumeration<?> e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while(e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if(c == '\0')
				sb.append(cs.getLiteral());
			else if(c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format a double.
	 * 
	 * @param x The double to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException if the conversion character is c, C, s, S, d, d, x, X, or o.
	 */
	public String sprintf(double x) throws IllegalArgumentException
	{
		Enumeration<?> e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while(e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if(c == '\0')
				sb.append(cs.getLiteral());
			else if(c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format a String.
	 * 
	 * @param x The String to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException if the conversion character is neither s nor S.
	 */
	public String sprintf(String x) throws IllegalArgumentException
	{
		Enumeration<?> e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while(e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if(c == '\0')
				sb.append(cs.getLiteral());
			else if(c == '%')
				sb.append("%");
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format an Object. Convert wrapper types to their primitive equivalents and call the appropriate internal formatting method. Convert Strings using an
	 * internal formatting method for Strings. Otherwise use the default formatter (use toString).
	 * 
	 * @param x the Object to format.
	 * @return the formatted String.
	 * @exception IllegalArgumentException if the conversion character is inappropriate for formatting an unwrapped value.
	 */
	public String sprintf(Object x) throws IllegalArgumentException
	{
		Enumeration<?> e = vFmt.elements();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuffer sb = new StringBuffer();
		while(e.hasMoreElements())
		{
			cs = (ConversionSpecification) e.nextElement();
			c = cs.getConversionCharacter();
			if(c == '\0')
				sb.append(cs.getLiteral());
			else if(c == '%')
				sb.append("%");
			else if(x instanceof Byte)
				sb.append(cs.internalsprintf(((Byte) x).byteValue()));
			else if(x instanceof Short)
				sb.append(cs.internalsprintf(((Short) x).shortValue()));
			else if(x instanceof Integer)
				sb.append(cs.internalsprintf(((Integer) x).intValue()));
			else if(x instanceof Long)
				sb.append(cs.internalsprintf(((Long) x).longValue()));
			else if(x instanceof Float)
				sb.append(cs.internalsprintf(((Float) x).floatValue()));
			else if(x instanceof Double)
				sb.append(cs.internalsprintf(((Double) x).doubleValue()));
			else if(x instanceof Character)
				sb.append(cs.internalsprintf(((Character) x).charValue()));
			else if(x instanceof String)
				sb.append(cs.internalsprintf((String) x));
			else
				sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * <p>
	 * ConversionSpecification allows the formatting of a single primitive or object embedded within a string. The formatting is controlled by a format string.
	 * Only one Java primitive or object can be formatted at a time.
	 * <p>
	 * A format string is a Java string that contains a control string. The control string starts at the first percent sign (%) in the string, provided that this
	 * percent sign
	 * <ol>
	 * <li>is not escaped protected by a matching % or is not an escape % character,
	 * <li>is not at the end of the format string, and
	 * <li>precedes a sequence of characters that parses as a valid control string.
	 * </ol>
	 * <p>
	 * A control string takes the form:
	 * 
	 * <pre>
	 *  % ['-+ #0]* [0..9]* { . [0..9]* }+
	 *                { [hlL] }+ [idfgGoxXeEcs]
	 * </pre>
	 * 
	 * <p>
	 * The behavior is like printf. One (hopefully the only) exception is that the minimum number of exponent digits is 3 instead of 2 for e and E formats when
	 * the optional L is used before the e, E, g, or G conversion character. The optional L does not imply conversion to a long long double.
	 */
	private class ConversionSpecification
	{
		/**
		 * Constructor. Used to prepare an instance to hold a literal, not a control string.
		 */
		ConversionSpecification()
		{}

		/**
		 * Constructor<?> for a conversion specification. The argument must begin with a % and end with the conversion character for the conversion specification.
		 * 
		 * @param fmtArg String specifying the conversion specification.
		 * @exception IllegalArgumentException if the input string is null, zero length, or otherwise malformed.
		 */
		ConversionSpecification(String fmtArg) throws IllegalArgumentException
		{
			if(fmtArg == null)
				throw new NullPointerException();
			if(fmtArg.length() == 0)
				throw new IllegalArgumentException("Control strings must have positive" + " lengths.");
			if(fmtArg.charAt(0) == '%')
			{
				fmt = fmtArg;
				pos = 1;
				setArgPosition();
				setFlagCharacters();
				setFieldWidth();
				setPrecision();
				setOptionalHL();
				if(setConversionCharacter())
				{
					if(pos == fmtArg.length())
					{
						if(leadingZeros && leftJustify)
							leadingZeros = false;
						if(precisionSet && leadingZeros)
							if(conversionCharacter == 'd' || conversionCharacter == 'i' || conversionCharacter == 'o' || conversionCharacter == 'x')
								leadingZeros = false;
					}
					else
						throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
				}
				else
					throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
			}
			else
				throw new IllegalArgumentException("Control strings must begin with %.");
		}

		/**
		 * Set the String for this instance.
		 * 
		 * @param s the String to store.
		 */
		void setLiteral(String s)
		{
			fmt = s;
		}

		/**
		 * Get the String for this instance. Translate any escape sequences.
		 * 
		 * @return s the stored String.
		 */
		String getLiteral()
		{
			StringBuffer sb = new StringBuffer();
			int i = 0;
			while(i < fmt.length())
				if(fmt.charAt(i) == '\\')
				{
					i++;
					if(i < fmt.length())
					{
						char c = fmt.charAt(i);
						switch(c)
						{
							case 'a':
								sb.append((char) 0x07);
								break;
							case 'b':
								sb.append('\b');
								break;
							case 'f':
								sb.append('\f');
								break;
							case 'n':
								sb.append(System.getProperty("line.separator"));
								break;
							case 'r':
								sb.append('\r');
								break;
							case 't':
								sb.append('\t');
								break;
							case 'v':
								sb.append((char) 0x0b);
								break;
							case '\\':
								sb.append('\\');
								break;
						}
						i++;
					}
					else
						sb.append('\\');
				}
				else
					i++;
			return fmt;
		}

		/**
		 * Get the conversion character that tells what type of control character this instance has.
		 * 
		 * @return the conversion character.
		 */
		char getConversionCharacter()
		{
			return conversionCharacter;
		}

		/**
		 * Check whether the specifier has a variable field width that is going to be set by an argument.
		 * 
		 * @return <code>true</code> if the conversion uses an * field width; otherwise <code>false</code>.
		 */
		boolean isVariableFieldWidth()
		{
			return variableFieldWidth;
		}

		/**
		 * Set the field width with an argument. A negative field width is taken as a - flag followed by a positive field width.
		 * 
		 * @param fw the field width.
		 */
		void setFieldWidthWithArg(int fw)
		{
			if(fw < 0)
				leftJustify = true;
			fieldWidthSet = true;
			fieldWidth = Math.abs(fw);
		}

		/**
		 * Check whether the specifier has a variable precision that is going to be set by an argument.
		 * 
		 * @return <code>true</code> if the conversion uses an * precision; otherwise <code>false</code>.
		 */
		boolean isVariablePrecision()
		{
			return variablePrecision;
		}

		/**
		 * Set the precision with an argument. A negative precision will be changed to zero.
		 * 
		 * @param pr the precision.
		 */
		void setPrecisionWithArg(int pr)
		{
			precisionSet = true;
			precision = Math.max(pr, 0);
		}

		/**
		 * Format an int argument using this conversion specification.
		 * 
		 * @param s the int to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException if the conversion character is f, e, E, g, or G.
		 */
		String internalsprintf(int s) throws IllegalArgumentException
		{
			String s2 = "";
			switch(conversionCharacter)
			{
				case 'd':
				case 'i':
					if(optionalh)
						s2 = printDFormat((short) s);
					else if(optionall)
						s2 = printDFormat((long) s);
					else
						s2 = printDFormat(s);
					break;
				case 'x':
				case 'X':
					if(optionalh)
						s2 = printXFormat((short) s);
					else if(optionall)
						s2 = printXFormat((long) s);
					else
						s2 = printXFormat(s);
					break;
				case 'o':
					if(optionalh)
						s2 = printOFormat((short) s);
					else if(optionall)
						s2 = printOFormat((long) s);
					else
						s2 = printOFormat(s);
					break;
				case 'c':
				case 'C':
					s2 = printCFormat((char) s);
					break;
				default:
					throw new IllegalArgumentException("Cannot format a int with a format using a " + conversionCharacter + " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a long argument using this conversion specification.
		 * 
		 * @param s the long to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException if the conversion character is f, e, E, g, or G.
		 */
		String internalsprintf(long s) throws IllegalArgumentException
		{
			String s2 = "";
			switch(conversionCharacter)
			{
				case 'd':
				case 'i':
					if(optionalh)
						s2 = printDFormat((short) s);
					else if(optionall)
						s2 = printDFormat(s);
					else
						s2 = printDFormat((int) s);
					break;
				case 'x':
				case 'X':
					if(optionalh)
						s2 = printXFormat((short) s);
					else if(optionall)
						s2 = printXFormat(s);
					else
						s2 = printXFormat((int) s);
					break;
				case 'o':
					if(optionalh)
						s2 = printOFormat((short) s);
					else if(optionall)
						s2 = printOFormat(s);
					else
						s2 = printOFormat((int) s);
					break;
				case 'c':
				case 'C':
					s2 = printCFormat((char) s);
					break;
				default:
					throw new IllegalArgumentException("Cannot format a long with a format using a " + conversionCharacter + " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a double argument using this conversion specification.
		 * 
		 * @param s the double to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException if the conversion character is c, C, s, S, i, d, x, X, or o.
		 */
		String internalsprintf(double s) throws IllegalArgumentException
		{
			String s2 = "";
			switch(conversionCharacter)
			{
				case 'f':
					s2 = printFFormat(s);
					break;
				case 'E':
				case 'e':
					s2 = printEFormat(s);
					break;
				case 'G':
				case 'g':
					s2 = printGFormat(s);
					break;
				default:
					throw new IllegalArgumentException("Cannot " + "format a double with a format using a " + conversionCharacter + " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a String argument using this conversion specification.
		 * 
		 * @param s the String to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException if the conversion character is neither s nor S.
		 */
		String internalsprintf(String s) throws IllegalArgumentException
		{
			String s2 = "";
			if(conversionCharacter == 's' || conversionCharacter == 'S')
				s2 = printSFormat(s);
			else
				throw new IllegalArgumentException("Cannot " + "format a String with a format using a " + conversionCharacter + " conversion character.");
			return s2;
		}

		/**
		 * Format an Object argument using this conversion specification.
		 * 
		 * @param s the Object to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException if the conversion character is neither s nor S.
		 */
		String internalsprintf(Object s)
		{
			String s2 = "";
			if(conversionCharacter == 's' || conversionCharacter == 'S')
				s2 = printSFormat(s.toString());
			else
				throw new IllegalArgumentException("Cannot format a String with a format using" + " a " + conversionCharacter + " conversion character.");
			return s2;
		}

		/**
		 * For f format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. '+'
		 * character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a non-negative input will be preceded
		 * with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character implies that padding to the field width will be
		 * done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the number of digits to appear after the radix character. Padding is with trailing 0s.
		 */
		private char[] fFormatDigits(double x)
		{
			// int defaultDigits=6;
			String sx;
			int i, j, k;
			int n1In, n2In;
			int expon = 0;
			boolean minusSign = false;
			if(x > 0.0)
				sx = Double.toString(x);
			else if(x < 0.0)
			{
				sx = Double.toString(-x);
				minusSign = true;
			}
			else
			{
				sx = Double.toString(x);
				if(sx.charAt(0) == '-')
				{
					minusSign = true;
					sx = sx.substring(1);
				}
			}
			int ePos = sx.indexOf('E');
			int rPos = sx.indexOf('.');
			if(rPos != -1)
				n1In = rPos;
			else if(ePos != -1)
				n1In = ePos;
			else
				n1In = sx.length();
			if(rPos != -1)
			{
				if(ePos != -1)
					n2In = ePos - rPos - 1;
				else
					n2In = sx.length() - rPos - 1;
			}
			else
				n2In = 0;
			if(ePos != -1)
			{
				int ie = ePos + 1;
				expon = 0;
				if(sx.charAt(ie) == '-')
				{
					for(++ie; ie < sx.length(); ie++)
						if(sx.charAt(ie) != '0')
							break;
					if(ie < sx.length())
						expon = -Integer.parseInt(sx.substring(ie));
				}
				else
				{
					if(sx.charAt(ie) == '+')
						++ie;
					for(; ie < sx.length(); ie++)
						if(sx.charAt(ie) != '0')
							break;
					if(ie < sx.length())
						expon = Integer.parseInt(sx.substring(ie));
				}
			}
			int p;
			if(precisionSet)
				p = precision;
			else
				p = defaultDigits - 1;
			char[] ca1 = sx.toCharArray();
			char[] ca2 = new char[n1In + n2In];
			char[] ca3, ca4, ca5;
			for(j = 0; j < n1In; j++)
				ca2[j] = ca1[j];
			i = j + 1;
			for(k = 0; k < n2In; j++, i++, k++)
				ca2[j] = ca1[i];
			if(n1In + expon <= 0)
			{
				ca3 = new char[-expon + n2In];
				for(j = 0, k = 0; k < -n1In - expon; k++, j++)
					ca3[j] = '0';
				for(i = 0; i < n1In + n2In; i++, j++)
					ca3[j] = ca2[i];
			}
			else
				ca3 = ca2;
			boolean carry = false;
			if(p < -expon + n2In)
			{
				if(expon < 0)
					i = p;
				else
					i = p + n1In;
				carry = checkForCarry(ca3, i);
				if(carry)
					carry = startSymbolicCarry(ca3, i - 1, 0);
			}
			if(n1In + expon <= 0)
			{
				ca4 = new char[2 + p];
				if(!carry)
					ca4[0] = '0';
				else
					ca4[0] = '1';
				if(alternateForm || !precisionSet || precision != 0)
				{
					ca4[1] = '.';
					for(i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++)
						ca4[j] = ca3[i];
					for(; j < ca4.length; j++)
						ca4[j] = '0';
				}
			}
			else
			{
				if(!carry)
				{
					if(alternateForm || !precisionSet || precision != 0)
						ca4 = new char[n1In + expon + p + 1];
					else
						ca4 = new char[n1In + expon];
					j = 0;
				}
				else
				{
					if(alternateForm || !precisionSet || precision != 0)
						ca4 = new char[n1In + expon + p + 2];
					else
						ca4 = new char[n1In + expon + 1];
					ca4[0] = '1';
					j = 1;
				}
				for(i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++)
					ca4[j] = ca3[i];
				for(; i < n1In + expon; i++, j++)
					ca4[j] = '0';
				if(alternateForm || !precisionSet || precision != 0)
				{
					ca4[j] = '.';
					j++;
					for(k = 0; i < ca3.length && k < p; i++, j++, k++)
						ca4[j] = ca3[i];
					for(; j < ca4.length; j++)
						ca4[j] = '0';
				}
			}
			int nZeros = 0;
			if(!leftJustify && leadingZeros)
			{
				int xThousands = 0;
				if(thousands)
				{
					int xlead = 0;
					if(ca4[0] == '+' || ca4[0] == '-' || ca4[0] == ' ')
						xlead = 1;
					int xdp = xlead;
					for(; xdp < ca4.length; xdp++)
						if(ca4[xdp] == '.')
							break;
					xThousands = (xdp - xlead) / 3;
				}
				if(fieldWidthSet)
					nZeros = fieldWidth - ca4.length;
				if(!minusSign && (leadingSign || leadingSpace) || minusSign)
					nZeros--;
				nZeros -= xThousands;
				if(nZeros < 0)
					nZeros = 0;
			}
			j = 0;
			if(!minusSign && (leadingSign || leadingSpace) || minusSign)
			{
				ca5 = new char[ca4.length + nZeros + 1];
				j++;
			}
			else
				ca5 = new char[ca4.length + nZeros];
			if(!minusSign)
			{
				if(leadingSign)
					ca5[0] = '+';
				if(leadingSpace)
					ca5[0] = ' ';
			}
			else
				ca5[0] = '-';
			for(i = 0; i < nZeros; i++, j++)
				ca5[j] = '0';
			for(i = 0; i < ca4.length; i++, j++)
				ca5[j] = ca4[i];

			int lead = 0;
			if(ca5[0] == '+' || ca5[0] == '-' || ca5[0] == ' ')
				lead = 1;
			int dp = lead;
			for(; dp < ca5.length; dp++)
				if(ca5[dp] == '.')
					break;
			int nThousands = (dp - lead) / 3;
			// Localize the decimal point.
			if(dp < ca5.length)
				ca5[dp] = dfs.getDecimalSeparator();
			char[] ca6 = ca5;
			if(thousands && nThousands > 0)
			{
				ca6 = new char[ca5.length + nThousands + lead];
				ca6[0] = ca5[0];
				for(i = lead, k = lead; i < dp; i++)
					if(i > 0 && (dp - i) % 3 == 0)
					{
						// ca6[k]=',';
						ca6[k] = dfs.getGroupingSeparator();
						ca6[k + 1] = ca5[i];
						k += 2;
					}
					else
					{
						ca6[k] = ca5[i];
						k++;
					}
				for(; i < ca5.length; i++, k++)
					ca6[k] = ca5[i];
			}
			return ca6;
		}

		/**
		 * An intermediate routine on the way to creating an f format String. The method decides whether the input double value is an infinity, not-a-number, or a
		 * finite double and formats each type of input appropriately.
		 * 
		 * @param x the double value to be formatted.
		 * @return the converted double value.
		 */
		private String fFormatString(double x)
		{
			char[] ca6, ca7;
			if(Double.isInfinite(x))
			{
				if(x == Double.POSITIVE_INFINITY)
				{
					if(leadingSign)
						ca6 = "+Inf".toCharArray();
					else if(leadingSpace)
						ca6 = " Inf".toCharArray();
					else
						ca6 = "Inf".toCharArray();
				}
				else
					ca6 = "-Inf".toCharArray();
			}
			else if(Double.isNaN(x))
			{
				if(leadingSign)
					ca6 = "+NaN".toCharArray();
				else if(leadingSpace)
					ca6 = " NaN".toCharArray();
				else
					ca6 = "NaN".toCharArray();
			}
			else
				ca6 = fFormatDigits(x);
			ca7 = applyFloatPadding(ca6, false);
			return new String(ca7);
		}

		/**
		 * For e format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. '+'
		 * character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a non-negative input will be preceded
		 * with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character implies that padding to the field width will be
		 * done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear after the radix character. Padding is with trailing 0s.
		 * 
		 * The behavior is like printf. One (hopefully the only) exception is that the minimum number of exponent digits is 3 instead of 2 for e and E formats when
		 * the optional L is used before the e, E, g, or G conversion character. The optional L does not imply conversion to a long long double.
		 */
		private char[] eFormatDigits(double x, char eChar)
		{
			char[] ca1, ca2, ca3;
			// int defaultDigits=6;
			String sx;
			int i, j, k, p;
			int expon = 0;
			int ePos, rPos, eSize;
			boolean minusSign = false;
			if(x > 0.0)
				sx = Double.toString(x);
			else if(x < 0.0)
			{
				sx = Double.toString(-x);
				minusSign = true;
			}
			else
			{
				sx = Double.toString(x);
				if(sx.charAt(0) == '-')
				{
					minusSign = true;
					sx = sx.substring(1);
				}
			}
			ePos = sx.indexOf('E');
			if(ePos == -1)
				ePos = sx.indexOf('e');
			rPos = sx.indexOf('.');
			if(ePos != -1)
			{
				int ie = ePos + 1;
				expon = 0;
				if(sx.charAt(ie) == '-')
				{
					for(++ie; ie < sx.length(); ie++)
						if(sx.charAt(ie) != '0')
							break;
					if(ie < sx.length())
						expon = -Integer.parseInt(sx.substring(ie));
				}
				else
				{
					if(sx.charAt(ie) == '+')
						++ie;
					for(; ie < sx.length(); ie++)
						if(sx.charAt(ie) != '0')
							break;
					if(ie < sx.length())
						expon = Integer.parseInt(sx.substring(ie));
				}
			}
			if(rPos != -1)
				expon += rPos - 1;
			if(precisionSet)
				p = precision;
			else
				p = defaultDigits - 1;
			if(rPos != -1 && ePos != -1)
				ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray();
			else if(rPos != -1)
				ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray();
			else if(ePos != -1)
				ca1 = sx.substring(0, ePos).toCharArray();
			else
				ca1 = sx.toCharArray();
			boolean carry = false;
			int i0 = 0;
			if(ca1[0] != '0')
				i0 = 0;
			else
				for(i0 = 0; i0 < ca1.length; i0++)
					if(ca1[i0] != '0')
						break;
			if(i0 + p < ca1.length - 1)
			{
				carry = checkForCarry(ca1, i0 + p + 1);
				if(carry)
					carry = startSymbolicCarry(ca1, i0 + p, i0);
				if(carry)
				{
					ca2 = new char[i0 + p + 1];
					ca2[i0] = '1';
					for(j = 0; j < i0; j++)
						ca2[j] = '0';
					for(i = i0, j = i0 + 1; j < p + 1; i++, j++)
						ca2[j] = ca1[i];
					expon++;
					ca1 = ca2;
				}
			}
			if(Math.abs(expon) < 100 && !optionalL)
				eSize = 4;
			else
				eSize = 5;
			if(alternateForm || !precisionSet || precision != 0)
				ca2 = new char[2 + p + eSize];
			else
				ca2 = new char[1 + eSize];
			if(ca1[0] != '0')
			{
				ca2[0] = ca1[0];
				j = 1;
			}
			else
			{
				for(j = 1; j < (ePos == -1 ? ca1.length : ePos); j++)
					if(ca1[j] != '0')
						break;
				if(ePos != -1 && j < ePos || ePos == -1 && j < ca1.length)
				{
					ca2[0] = ca1[j];
					expon -= j;
					j++;
				}
				else
				{
					ca2[0] = '0';
					j = 2;
				}
			}
			if(alternateForm || !precisionSet || precision != 0)
			{
				ca2[1] = '.';
				i = 2;
			}
			else
				i = 1;
			for(k = 0; k < p && j < ca1.length; j++, i++, k++)
				ca2[i] = ca1[j];
			for(; i < ca2.length - eSize; i++)
				ca2[i] = '0';
			ca2[i++] = eChar;
			if(expon < 0)
				ca2[i++] = '-';
			else
				ca2[i++] = '+';
			expon = Math.abs(expon);
			if(expon >= 100)
			{
				switch(expon / 100)
				{
					case 1:
						ca2[i] = '1';
						break;
					case 2:
						ca2[i] = '2';
						break;
					case 3:
						ca2[i] = '3';
						break;
					case 4:
						ca2[i] = '4';
						break;
					case 5:
						ca2[i] = '5';
						break;
					case 6:
						ca2[i] = '6';
						break;
					case 7:
						ca2[i] = '7';
						break;
					case 8:
						ca2[i] = '8';
						break;
					case 9:
						ca2[i] = '9';
						break;
				}
				i++;
			}
			switch(expon % 100 / 10)
			{
				case 0:
					ca2[i] = '0';
					break;
				case 1:
					ca2[i] = '1';
					break;
				case 2:
					ca2[i] = '2';
					break;
				case 3:
					ca2[i] = '3';
					break;
				case 4:
					ca2[i] = '4';
					break;
				case 5:
					ca2[i] = '5';
					break;
				case 6:
					ca2[i] = '6';
					break;
				case 7:
					ca2[i] = '7';
					break;
				case 8:
					ca2[i] = '8';
					break;
				case 9:
					ca2[i] = '9';
					break;
			}
			i++;
			switch(expon % 10)
			{
				case 0:
					ca2[i] = '0';
					break;
				case 1:
					ca2[i] = '1';
					break;
				case 2:
					ca2[i] = '2';
					break;
				case 3:
					ca2[i] = '3';
					break;
				case 4:
					ca2[i] = '4';
					break;
				case 5:
					ca2[i] = '5';
					break;
				case 6:
					ca2[i] = '6';
					break;
				case 7:
					ca2[i] = '7';
					break;
				case 8:
					ca2[i] = '8';
					break;
				case 9:
					ca2[i] = '9';
					break;
			}
			int nZeros = 0;
			if(!leftJustify && leadingZeros)
			{
				int xThousands = 0;
				if(thousands)
				{
					int xlead = 0;
					if(ca2[0] == '+' || ca2[0] == '-' || ca2[0] == ' ')
						xlead = 1;
					int xdp = xlead;
					for(; xdp < ca2.length; xdp++)
						if(ca2[xdp] == '.')
							break;
					xThousands = (xdp - xlead) / 3;
				}
				if(fieldWidthSet)
					nZeros = fieldWidth - ca2.length;
				if(!minusSign && (leadingSign || leadingSpace) || minusSign)
					nZeros--;
				nZeros -= xThousands;
				if(nZeros < 0)
					nZeros = 0;
			}
			j = 0;
			if(!minusSign && (leadingSign || leadingSpace) || minusSign)
			{
				ca3 = new char[ca2.length + nZeros + 1];
				j++;
			}
			else
				ca3 = new char[ca2.length + nZeros];
			if(!minusSign)
			{
				if(leadingSign)
					ca3[0] = '+';
				if(leadingSpace)
					ca3[0] = ' ';
			}
			else
				ca3[0] = '-';
			for(k = 0; k < nZeros; j++, k++)
				ca3[j] = '0';
			for(i = 0; i < ca2.length && j < ca3.length; i++, j++)
				ca3[j] = ca2[i];

			int lead = 0;
			if(ca3[0] == '+' || ca3[0] == '-' || ca3[0] == ' ')
				lead = 1;
			int dp = lead;
			for(; dp < ca3.length; dp++)
				if(ca3[dp] == '.')
					break;
			int nThousands = dp / 3;
			// Localize the decimal point.
			if(dp < ca3.length)
				ca3[dp] = dfs.getDecimalSeparator();
			char[] ca4 = ca3;
			if(thousands && nThousands > 0)
			{
				ca4 = new char[ca3.length + nThousands + lead];
				ca4[0] = ca3[0];
				for(i = lead, k = lead; i < dp; i++)
					if(i > 0 && (dp - i) % 3 == 0)
					{
						// ca4[k]=',';
						ca4[k] = dfs.getGroupingSeparator();
						ca4[k + 1] = ca3[i];
						k += 2;
					}
					else
					{
						ca4[k] = ca3[i];
						k++;
					}
				for(; i < ca3.length; i++, k++)
					ca4[k] = ca3[i];
			}
			return ca4;
		}

		/**
		 * Check to see if the digits that are going to be truncated because of the precision should force a round in the preceding digits.
		 * 
		 * @param ca1 the array of digits
		 * @param icarry the index of the first digit that is to be truncated from the print
		 * @return <code>true</code> if the truncation forces a round that will change the print
		 */
		private boolean checkForCarry(char[] ca1, int icarry)
		{
			boolean carry = false;
			if(icarry < ca1.length)
				if(ca1[icarry] == '6' || ca1[icarry] == '7' || ca1[icarry] == '8' || ca1[icarry] == '9')
					carry = true;
				else if(ca1[icarry] == '5')
				{
					int ii = icarry + 1;
					for(; ii < ca1.length; ii++)
						if(ca1[ii] != '0')
							break;
					carry = ii < ca1.length;
					if(!carry && icarry > 0)
						carry = ca1[icarry - 1] == '1' || ca1[icarry - 1] == '3' || ca1[icarry - 1] == '5' || ca1[icarry - 1] == '7' || ca1[icarry - 1] == '9';
				}
			return carry;
		}

		/**
		 * Start the symbolic carry process. The process is not quite finished because the symbolic carry may change the length of the string and change the
		 * exponent (in e format).
		 * 
		 * @param cLast index of the last digit changed by the round
		 * @param cFirst index of the first digit allowed to be changed by this phase of the round
		 * @return <code>true</code> if the carry forces a round that will change the print still more
		 */
		private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst)
		{
			boolean carry = true;
			for(int i = cLast; carry && i >= cFirst; i--)
			{
				carry = false;
				switch(ca[i])
				{
					case '0':
						ca[i] = '1';
						break;
					case '1':
						ca[i] = '2';
						break;
					case '2':
						ca[i] = '3';
						break;
					case '3':
						ca[i] = '4';
						break;
					case '4':
						ca[i] = '5';
						break;
					case '5':
						ca[i] = '6';
						break;
					case '6':
						ca[i] = '7';
						break;
					case '7':
						ca[i] = '8';
						break;
					case '8':
						ca[i] = '9';
						break;
					case '9':
						ca[i] = '0';
						carry = true;
						break;
				}
			}
			return carry;
		}

		/**
		 * An intermediate routine on the way to creating an e format String. The method decides whether the input double value is an infinity, not-a-number, or a
		 * finite double and formats each type of input appropriately.
		 * 
		 * @param x the double value to be formatted.
		 * @param eChar an 'e' or 'E' to use in the converted double value.
		 * @return the converted double value.
		 */
		private String eFormatString(double x, char eChar)
		{
			char[] ca4, ca5;
			if(Double.isInfinite(x))
			{
				if(x == Double.POSITIVE_INFINITY)
				{
					if(leadingSign)
						ca4 = "+Inf".toCharArray();
					else if(leadingSpace)
						ca4 = " Inf".toCharArray();
					else
						ca4 = "Inf".toCharArray();
				}
				else
					ca4 = "-Inf".toCharArray();
			}
			else if(Double.isNaN(x))
			{
				if(leadingSign)
					ca4 = "+NaN".toCharArray();
				else if(leadingSpace)
					ca4 = " NaN".toCharArray();
				else
					ca4 = "NaN".toCharArray();
			}
			else
				ca4 = eFormatDigits(x, eChar);
			ca5 = applyFloatPadding(ca4, false);
			return new String(ca5);
		}

		/**
		 * Apply zero or blank, left or right padding.
		 * 
		 * @param ca4 array of characters before padding is finished
		 * @param noDigits NaN or signed Inf
		 * @return a padded array of characters
		 */
		private char[] applyFloatPadding(char[] ca4, boolean noDigits)
		{
			char[] ca5 = ca4;
			if(fieldWidthSet)
			{
				int i, j, nBlanks;
				if(leftJustify)
				{
					nBlanks = fieldWidth - ca4.length;
					if(nBlanks > 0)
					{
						ca5 = new char[ca4.length + nBlanks];
						for(i = 0; i < ca4.length; i++)
							ca5[i] = ca4[i];
						for(j = 0; j < nBlanks; j++, i++)
							ca5[i] = ' ';
					}
				}
				else if(!leadingZeros || noDigits)
				{
					nBlanks = fieldWidth - ca4.length;
					if(nBlanks > 0)
					{
						ca5 = new char[ca4.length + nBlanks];
						for(i = 0; i < nBlanks; i++)
							ca5[i] = ' ';
						for(j = 0; j < ca4.length; i++, j++)
							ca5[i] = ca4[j];
					}
				}
				else if(leadingZeros)
				{
					nBlanks = fieldWidth - ca4.length;
					if(nBlanks > 0)
					{
						ca5 = new char[ca4.length + nBlanks];
						i = 0;
						j = 0;
						if(ca4[0] == '-')
						{
							ca5[0] = '-';
							i++;
							j++;
						}
						for(int k = 0; k < nBlanks; i++, k++)
							ca5[i] = '0';
						for(; j < ca4.length; i++, j++)
							ca5[i] = ca4[j];
					}
				}
			}
			return ca5;
		}

		/**
		 * Format method for the f conversion character.
		 * 
		 * @param x the double to format.
		 * @return the formatted String.
		 */
		private String printFFormat(double x)
		{
			return fFormatString(x);
		}

		/**
		 * Format method for the e or E conversion character.
		 * 
		 * @param x the double to format.
		 * @return the formatted String.
		 */
		private String printEFormat(double x)
		{
			if(conversionCharacter == 'e')
				return eFormatString(x, 'e');
			return eFormatString(x, 'E');
		}

		/**
		 * Format method for the g conversion character.
		 * 
		 * For g format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. '+'
		 * character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a non-negative input will be preceded
		 * with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character implies that padding to the field width will be
		 * done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear after the radix character. Padding is with trailing 0s.
		 * 
		 * @param x the double to format.
		 * @return the formatted String.
		 */
		private String printGFormat(double x)
		{
			String sx, sy, sz, ret;
			int savePrecision = precision;
			int i;
			char[] ca4, ca5;
			if(Double.isInfinite(x))
			{
				if(x == Double.POSITIVE_INFINITY)
				{
					if(leadingSign)
						ca4 = "+Inf".toCharArray();
					else if(leadingSpace)
						ca4 = " Inf".toCharArray();
					else
						ca4 = "Inf".toCharArray();
				}
				else
					ca4 = "-Inf".toCharArray();
			}
			else if(Double.isNaN(x))
			{
				if(leadingSign)
					ca4 = "+NaN".toCharArray();
				else if(leadingSpace)
					ca4 = " NaN".toCharArray();
				else
					ca4 = "NaN".toCharArray();
			}
			else
			{
				if(!precisionSet)
					precision = defaultDigits;
				if(precision == 0)
					precision = 1;
				int ePos = -1;
				if(conversionCharacter == 'g')
				{
					sx = eFormatString(x, 'e').trim();
					ePos = sx.indexOf('e');
				}
				else
				{
					sx = eFormatString(x, 'E').trim();
					ePos = sx.indexOf('E');
				}
				i = ePos + 1;
				int expon = 0;
				if(sx.charAt(i) == '-')
				{
					for(++i; i < sx.length(); i++)
						if(sx.charAt(i) != '0')
							break;
					if(i < sx.length())
						expon = -Integer.parseInt(sx.substring(i));
				}
				else
				{
					if(sx.charAt(i) == '+')
						++i;
					for(; i < sx.length(); i++)
						if(sx.charAt(i) != '0')
							break;
					if(i < sx.length())
						expon = Integer.parseInt(sx.substring(i));
				}
				// Trim trailing zeros.
				// If the radix character is not followed by
				// a digit, trim it, too.
				if(!alternateForm)
				{
					if(expon >= -4 && expon < precision)
						sy = fFormatString(x).trim();
					else
						sy = sx.substring(0, ePos);
					i = sy.length() - 1;
					for(; i >= 0; i--)
						if(sy.charAt(i) != '0')
							break;
					if(i >= 0 && sy.charAt(i) == '.')
						i--;
					if(i == -1)
						sz = "0";
					else if(!Character.isDigit(sy.charAt(i)))
						sz = sy.substring(0, i + 1) + "0";
					else
						sz = sy.substring(0, i + 1);
					if(expon >= -4 && expon < precision)
						ret = sz;
					else
						ret = sz + sx.substring(ePos);
				}
				else if(expon >= -4 && expon < precision)
					ret = fFormatString(x).trim();
				else
					ret = sx;
				// leading space was trimmed off during
				// construction
				if(leadingSpace)
					if(x >= 0)
						ret = " " + ret;
				ca4 = ret.toCharArray();
			}
			// Pad with blanks or zeros.
			ca5 = applyFloatPadding(ca4, false);
			precision = savePrecision;
			return new String(ca5);
		}

		/**
		 * Format method for the d conversion specifer and short argument.
		 * 
		 * For d format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. A
		 * '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a non-negative input will be preceded
		 * with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character implies that padding to the field width will be
		 * done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the short to format.
		 * @return the formatted String.
		 */
		private String printDFormat(short x)
		{
			return printDFormat(Short.toString(x));
		}

		/**
		 * Format method for the d conversion character and long argument.
		 * 
		 * For d format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. A
		 * '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a non-negative input will be preceded
		 * with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character implies that padding to the field width will be
		 * done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the long to format.
		 * @return the formatted String.
		 */
		private String printDFormat(long x)
		{
			return printDFormat(Long.toString(x));
		}

		/**
		 * Format method for the d conversion character and int argument.
		 * 
		 * For d format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. A
		 * '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a non-negative input will be preceded
		 * with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character implies that padding to the field width will be
		 * done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the int to format.
		 * @return the formatted String.
		 */
		private String printDFormat(int x)
		{
			return printDFormat(Integer.toString(x));
		}

		/**
		 * Utility method for formatting using the d conversion character.
		 * 
		 * @param sx the String to format, the result of converting a short, int, or long to a String.
		 * @return the formatted String.
		 */
		private String printDFormat(String sx)
		{
			int nLeadingZeros = 0;
			int nBlanks = 0, n = 0;
			int i = 0, jFirst = 0;
			boolean neg = sx.charAt(0) == '-';
			if(sx.equals("0") && precisionSet && precision == 0)
				sx = "";
			if(!neg)
			{
				if(precisionSet && sx.length() < precision)
					nLeadingZeros = precision - sx.length();
			}
			else if(precisionSet && sx.length() - 1 < precision)
				nLeadingZeros = precision - sx.length() + 1;
			if(nLeadingZeros < 0)
				nLeadingZeros = 0;
			if(fieldWidthSet)
			{
				nBlanks = fieldWidth - nLeadingZeros - sx.length();
				if(!neg && (leadingSign || leadingSpace))
					nBlanks--;
			}
			if(nBlanks < 0)
				nBlanks = 0;
			if(leadingSign)
				n++;
			else if(leadingSpace)
				n++;
			n += nBlanks;
			n += nLeadingZeros;
			n += sx.length();
			char[] ca = new char[n];
			if(leftJustify)
			{
				if(neg)
					ca[i++] = '-';
				else if(leadingSign)
					ca[i++] = '+';
				else if(leadingSpace)
					ca[i++] = ' ';
				char[] csx = sx.toCharArray();
				jFirst = neg ? 1 : 0;
				for(int j = 0; j < nLeadingZeros; i++, j++)
					ca[i] = '0';
				for(int j = jFirst; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for(int j = 0; j < nBlanks; i++, j++)
					ca[i] = ' ';
			}
			else
			{
				if(!leadingZeros)
				{
					for(i = 0; i < nBlanks; i++)
						ca[i] = ' ';
					if(neg)
						ca[i++] = '-';
					else if(leadingSign)
						ca[i++] = '+';
					else if(leadingSpace)
						ca[i++] = ' ';
				}
				else
				{
					if(neg)
						ca[i++] = '-';
					else if(leadingSign)
						ca[i++] = '+';
					else if(leadingSpace)
						ca[i++] = ' ';
					for(int j = 0; j < nBlanks; j++, i++)
						ca[i] = '0';
				}
				for(int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				jFirst = neg ? 1 : 0;
				for(int j = jFirst; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			return new String(ca);
		}

		/**
		 * Format method for the x conversion character and short argument.
		 * 
		 * For x format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. The
		 * '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the short to format.
		 * @return the formatted String.
		 */
		private String printXFormat(short x)
		{
			String sx = null;
			if(x == Short.MIN_VALUE)
				sx = "8000";
			else if(x < 0)
			{
				String t;
				if(x == Short.MIN_VALUE)
					t = "0";
				else
				{
					t = Integer.toString(~(-x - 1) ^ Short.MIN_VALUE, 16);
					if(t.charAt(0) == 'F' || t.charAt(0) == 'f')
						t = t.substring(16, 32);
				}
				switch(t.length())
				{
					case 1:
						sx = "800" + t;
						break;
					case 2:
						sx = "80" + t;
						break;
					case 3:
						sx = "8" + t;
						break;
					case 4:
						switch(t.charAt(0))
						{
							case '1':
								sx = "9" + t.substring(1, 4);
								break;
							case '2':
								sx = "a" + t.substring(1, 4);
								break;
							case '3':
								sx = "b" + t.substring(1, 4);
								break;
							case '4':
								sx = "c" + t.substring(1, 4);
								break;
							case '5':
								sx = "d" + t.substring(1, 4);
								break;
							case '6':
								sx = "e" + t.substring(1, 4);
								break;
							case '7':
								sx = "f" + t.substring(1, 4);
								break;
						}
						break;
				}
			}
			else
				sx = Integer.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Format method for the x conversion character and long argument.
		 * 
		 * For x format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. The
		 * '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the long to format.
		 * @return the formatted String.
		 */
		private String printXFormat(long x)
		{
			String sx = null;
			if(x == Long.MIN_VALUE)
				sx = "8000000000000000";
			else if(x < 0)
			{
				String t = Long.toString(~(-x - 1) ^ Long.MIN_VALUE, 16);
				switch(t.length())
				{
					case 1:
						sx = "800000000000000" + t;
						break;
					case 2:
						sx = "80000000000000" + t;
						break;
					case 3:
						sx = "8000000000000" + t;
						break;
					case 4:
						sx = "800000000000" + t;
						break;
					case 5:
						sx = "80000000000" + t;
						break;
					case 6:
						sx = "8000000000" + t;
						break;
					case 7:
						sx = "800000000" + t;
						break;
					case 8:
						sx = "80000000" + t;
						break;
					case 9:
						sx = "8000000" + t;
						break;
					case 10:
						sx = "800000" + t;
						break;
					case 11:
						sx = "80000" + t;
						break;
					case 12:
						sx = "8000" + t;
						break;
					case 13:
						sx = "800" + t;
						break;
					case 14:
						sx = "80" + t;
						break;
					case 15:
						sx = "8" + t;
						break;
					case 16:
						switch(t.charAt(0))
						{
							case '1':
								sx = "9" + t.substring(1, 16);
								break;
							case '2':
								sx = "a" + t.substring(1, 16);
								break;
							case '3':
								sx = "b" + t.substring(1, 16);
								break;
							case '4':
								sx = "c" + t.substring(1, 16);
								break;
							case '5':
								sx = "d" + t.substring(1, 16);
								break;
							case '6':
								sx = "e" + t.substring(1, 16);
								break;
							case '7':
								sx = "f" + t.substring(1, 16);
								break;
						}
						break;
				}
			}
			else
				sx = Long.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Format method for the x conversion character and int argument.
		 * 
		 * For x format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. The
		 * '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the int to format.
		 * @return the formatted String.
		 */
		private String printXFormat(int x)
		{
			String sx = null;
			if(x == Integer.MIN_VALUE)
				sx = "80000000";
			else if(x < 0)
			{
				String t = Integer.toString(~(-x - 1) ^ Integer.MIN_VALUE, 16);
				switch(t.length())
				{
					case 1:
						sx = "8000000" + t;
						break;
					case 2:
						sx = "800000" + t;
						break;
					case 3:
						sx = "80000" + t;
						break;
					case 4:
						sx = "8000" + t;
						break;
					case 5:
						sx = "800" + t;
						break;
					case 6:
						sx = "80" + t;
						break;
					case 7:
						sx = "8" + t;
						break;
					case 8:
						switch(t.charAt(0))
						{
							case '1':
								sx = "9" + t.substring(1, 8);
								break;
							case '2':
								sx = "a" + t.substring(1, 8);
								break;
							case '3':
								sx = "b" + t.substring(1, 8);
								break;
							case '4':
								sx = "c" + t.substring(1, 8);
								break;
							case '5':
								sx = "d" + t.substring(1, 8);
								break;
							case '6':
								sx = "e" + t.substring(1, 8);
								break;
							case '7':
								sx = "f" + t.substring(1, 8);
								break;
						}
						break;
				}
			}
			else
				sx = Integer.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Utility method for formatting using the x conversion character.
		 * 
		 * @param sx the String to format, the result of converting a short, int, or long to a String.
		 * @return the formatted String.
		 */
		private String printXFormat(String sx)
		{
			int nLeadingZeros = 0;
			int nBlanks = 0;
			if(sx.equals("0") && precisionSet && precision == 0)
				sx = "";
			if(precisionSet)
				nLeadingZeros = precision - sx.length();
			if(nLeadingZeros < 0)
				nLeadingZeros = 0;
			if(fieldWidthSet)
			{
				nBlanks = fieldWidth - nLeadingZeros - sx.length();
				if(alternateForm)
					nBlanks = nBlanks - 2;
			}
			if(nBlanks < 0)
				nBlanks = 0;
			int n = 0;
			if(alternateForm)
				n += 2;
			n += nLeadingZeros;
			n += sx.length();
			n += nBlanks;
			char[] ca = new char[n];
			int i = 0;
			if(leftJustify)
			{
				if(alternateForm)
				{
					ca[i++] = '0';
					ca[i++] = 'x';
				}
				for(int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for(int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for(int j = 0; j < nBlanks; j++, i++)
					ca[i] = ' ';
			}
			else
			{
				if(!leadingZeros)
					for(int j = 0; j < nBlanks; j++, i++)
						ca[i] = ' ';
				if(alternateForm)
				{
					ca[i++] = '0';
					ca[i++] = 'x';
				}
				if(leadingZeros)
					for(int j = 0; j < nBlanks; j++, i++)
						ca[i] = '0';
				for(int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for(int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			String caReturn = new String(ca);
			if(conversionCharacter == 'X')
				caReturn = caReturn.toUpperCase();
			return caReturn;
		}

		/**
		 * Format method for the o conversion character and short argument.
		 * 
		 * For o format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. The
		 * '#' flag character means that the output begins with a leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the short to format.
		 * @return the formatted String.
		 */
		private String printOFormat(short x)
		{
			String sx = null;
			if(x == Short.MIN_VALUE)
				sx = "100000";
			else if(x < 0)
			{
				String t = Integer.toString(~(-x - 1) ^ Short.MIN_VALUE, 8);
				switch(t.length())
				{
					case 1:
						sx = "10000" + t;
						break;
					case 2:
						sx = "1000" + t;
						break;
					case 3:
						sx = "100" + t;
						break;
					case 4:
						sx = "10" + t;
						break;
					case 5:
						sx = "1" + t;
						break;
				}
			}
			else
				sx = Integer.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Format method for the o conversion character and long argument.
		 * 
		 * For o format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. The
		 * '#' flag character means that the output begins with a leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the long to format.
		 * @return the formatted String.
		 */
		private String printOFormat(long x)
		{
			String sx = null;
			if(x == Long.MIN_VALUE)
				sx = "1000000000000000000000";
			else if(x < 0)
			{
				String t = Long.toString(~(-x - 1) ^ Long.MIN_VALUE, 8);
				switch(t.length())
				{
					case 1:
						sx = "100000000000000000000" + t;
						break;
					case 2:
						sx = "10000000000000000000" + t;
						break;
					case 3:
						sx = "1000000000000000000" + t;
						break;
					case 4:
						sx = "100000000000000000" + t;
						break;
					case 5:
						sx = "10000000000000000" + t;
						break;
					case 6:
						sx = "1000000000000000" + t;
						break;
					case 7:
						sx = "100000000000000" + t;
						break;
					case 8:
						sx = "10000000000000" + t;
						break;
					case 9:
						sx = "1000000000000" + t;
						break;
					case 10:
						sx = "100000000000" + t;
						break;
					case 11:
						sx = "10000000000" + t;
						break;
					case 12:
						sx = "1000000000" + t;
						break;
					case 13:
						sx = "100000000" + t;
						break;
					case 14:
						sx = "10000000" + t;
						break;
					case 15:
						sx = "1000000" + t;
						break;
					case 16:
						sx = "100000" + t;
						break;
					case 17:
						sx = "10000" + t;
						break;
					case 18:
						sx = "1000" + t;
						break;
					case 19:
						sx = "100" + t;
						break;
					case 20:
						sx = "10" + t;
						break;
					case 21:
						sx = "1" + t;
						break;
				}
			}
			else
				sx = Long.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Format method for the o conversion character and int argument.
		 * 
		 * For o format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on the left. The
		 * '#' flag character means that the output begins with a leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x the int to format.
		 * @return the formatted String.
		 */
		private String printOFormat(int x)
		{
			String sx = null;
			if(x == Integer.MIN_VALUE)
				sx = "20000000000";
			else if(x < 0)
			{
				String t = Integer.toString(~(-x - 1) ^ Integer.MIN_VALUE, 8);
				switch(t.length())
				{
					case 1:
						sx = "2000000000" + t;
						break;
					case 2:
						sx = "200000000" + t;
						break;
					case 3:
						sx = "20000000" + t;
						break;
					case 4:
						sx = "2000000" + t;
						break;
					case 5:
						sx = "200000" + t;
						break;
					case 6:
						sx = "20000" + t;
						break;
					case 7:
						sx = "2000" + t;
						break;
					case 8:
						sx = "200" + t;
						break;
					case 9:
						sx = "20" + t;
						break;
					case 10:
						sx = "2" + t;
						break;
					case 11:
						sx = "3" + t.substring(1);
						break;
				}
			}
			else
				sx = Integer.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Utility method for formatting using the o conversion character.
		 * 
		 * @param sx the String to format, the result of converting a short, int, or long to a String.
		 * @return the formatted String.
		 */
		private String printOFormat(String sx)
		{
			int nLeadingZeros = 0;
			int nBlanks = 0;
			if(sx.equals("0") && precisionSet && precision == 0)
				sx = "";
			if(precisionSet)
				nLeadingZeros = precision - sx.length();
			if(alternateForm)
				nLeadingZeros++;
			if(nLeadingZeros < 0)
				nLeadingZeros = 0;
			if(fieldWidthSet)
				nBlanks = fieldWidth - nLeadingZeros - sx.length();
			if(nBlanks < 0)
				nBlanks = 0;
			int n = nLeadingZeros + sx.length() + nBlanks;
			char[] ca = new char[n];
			int i;
			if(leftJustify)
			{
				for(i = 0; i < nLeadingZeros; i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for(int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for(int j = 0; j < nBlanks; j++, i++)
					ca[i] = ' ';
			}
			else
			{
				if(leadingZeros)
					for(i = 0; i < nBlanks; i++)
						ca[i] = '0';
				else
					for(i = 0; i < nBlanks; i++)
						ca[i] = ' ';
				for(int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for(int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			return new String(ca);
		}

		/**
		 * Format method for the c conversion character and char argument.
		 * 
		 * The only flag character that affects c format is the '-', meaning that the output should be left justified within the field. The default is to pad with
		 * blanks on the left.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. Padding is with blanks by default. The default width is 1.
		 * 
		 * The precision, if set, is ignored.
		 * 
		 * @param x the char to format.
		 * @return the formatted String.
		 */
		private String printCFormat(char x)
		{
			int nPrint = 1;
			int width = fieldWidth;
			if(!fieldWidthSet)
				width = nPrint;
			char[] ca = new char[width];
			int i = 0;
			if(leftJustify)
			{
				ca[0] = x;
				for(i = 1; i <= width - nPrint; i++)
					ca[i] = ' ';
			}
			else
			{
				for(i = 0; i < width - nPrint; i++)
					ca[i] = ' ';
				ca[i] = x;
			}
			return new String(ca);
		}

		/**
		 * Format method for the s conversion character and String argument.
		 * 
		 * The only flag character that affects s format is the '-', meaning that the output should be left justified within the field. The default is to pad with
		 * blanks on the left.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is the smaller of the number of characters in the the input and
		 * the precision. Padding is with blanks by default.
		 * 
		 * The precision, if set, specifies the maximum number of characters to be printed from the string. A null digit string is treated as a 0. The default is
		 * not to set a maximum number of characters to be printed.
		 * 
		 * @param x the String to format.
		 * @return the formatted String.
		 */
		private String printSFormat(String x)
		{
			int nPrint = x.length();
			int width = fieldWidth;
			if(precisionSet && nPrint > precision)
				nPrint = precision;
			if(!fieldWidthSet)
				width = nPrint;
			int n = 0;
			if(width > nPrint)
				n += width - nPrint;
			if(nPrint >= x.length())
				n += x.length();
			else
				n += nPrint;
			char[] ca = new char[n];
			int i = 0;
			if(leftJustify)
			{
				if(nPrint >= x.length())
				{
					char[] csx = x.toCharArray();
					for(i = 0; i < x.length(); i++)
						ca[i] = csx[i];
				}
				else
				{
					char[] csx = x.substring(0, nPrint).toCharArray();
					for(i = 0; i < nPrint; i++)
						ca[i] = csx[i];
				}
				for(int j = 0; j < width - nPrint; j++, i++)
					ca[i] = ' ';
			}
			else
			{
				for(i = 0; i < width - nPrint; i++)
					ca[i] = ' ';
				if(nPrint >= x.length())
				{
					char[] csx = x.toCharArray();
					for(int j = 0; j < x.length(); i++, j++)
						ca[i] = csx[j];
				}
				else
				{
					char[] csx = x.substring(0, nPrint).toCharArray();
					for(int j = 0; j < nPrint; i++, j++)
						ca[i] = csx[j];
				}
			}
			return new String(ca);
		}

		/**
		 * Check for a conversion character. If it is there, store it.
		 * 
		 * @param x the String to format.
		 * @return <code>true</code> if the conversion character is there, and <code>false</code> otherwise.
		 */
		private boolean setConversionCharacter()
		{
			/* idfgGoxXeEcs */
			boolean ret = false;
			conversionCharacter = '\0';
			if(pos < fmt.length())
			{
				char c = fmt.charAt(pos);
				if(c == 'i' || c == 'd' || c == 'f' || c == 'g' || c == 'G' || c == 'o' || c == 'x' || c == 'X' || c == 'e' || c == 'E' || c == 'c' || c == 's' || c == '%')
				{
					conversionCharacter = c;
					pos++;
					ret = true;
				}
			}
			return ret;
		}

		/**
		 * Check for an h, l, or L in a format. An L is used to control the minimum number of digits in an exponent when using floating point formats. An l or h is
		 * used to control conversion of the input to a long or short, respectively, before formatting. If any of these is present, store them.
		 */
		private void setOptionalHL()
		{
			optionalh = false;
			optionall = false;
			optionalL = false;
			if(pos < fmt.length())
			{
				char c = fmt.charAt(pos);
				if(c == 'h')
				{
					optionalh = true;
					pos++;
				}
				else if(c == 'l')
				{
					optionall = true;
					pos++;
				}
				else if(c == 'L')
				{
					optionalL = true;
					pos++;
				}
			}
		}

		/**
		 * Set the precision.
		 */
		private void setPrecision()
		{
			int firstPos = pos;
			precisionSet = false;
			if(pos < fmt.length() && fmt.charAt(pos) == '.')
			{
				pos++;
				if(pos < fmt.length() && fmt.charAt(pos) == '*')
				{
					pos++;
					if(!setPrecisionArgPosition())
					{
						variablePrecision = true;
						precisionSet = true;
					}
					return;
				}
				while(pos < fmt.length())
				{
					char c = fmt.charAt(pos);
					if(Character.isDigit(c))
						pos++;
					else
						break;
				}
				if(pos > firstPos + 1)
				{
					String sz = fmt.substring(firstPos + 1, pos);
					precision = Integer.parseInt(sz);
					precisionSet = true;
				}
			}
		}

		/**
		 * Set the field width.
		 */
		private void setFieldWidth()
		{
			int firstPos = pos;
			fieldWidth = 0;
			fieldWidthSet = false;
			if(pos < fmt.length() && fmt.charAt(pos) == '*')
			{
				pos++;
				if(!setFieldWidthArgPosition())
				{
					variableFieldWidth = true;
					fieldWidthSet = true;
				}
			}
			else
			{
				while(pos < fmt.length())
				{
					char c = fmt.charAt(pos);
					if(Character.isDigit(c))
						pos++;
					else
						break;
				}
				if(firstPos < pos && firstPos < fmt.length())
				{
					String sz = fmt.substring(firstPos, pos);
					fieldWidth = Integer.parseInt(sz);
					fieldWidthSet = true;
				}
			}
		}

		/**
		 * Store the digits <code>n</code> in %n$ forms.
		 */
		private void setArgPosition()
		{
			int xPos;
			for(xPos = pos; xPos < fmt.length(); xPos++)
				if(!Character.isDigit(fmt.charAt(xPos)))
					break;
			if(xPos > pos && xPos < fmt.length())
				if(fmt.charAt(xPos) == '$')
				{
					positionalSpecification = true;
					argumentPosition = Integer.parseInt(fmt.substring(pos, xPos));
					pos = xPos + 1;
				}
		}

		/**
		 * Store the digits <code>n</code> in *n$ forms.
		 */
		private boolean setFieldWidthArgPosition()
		{
			boolean ret = false;
			int xPos;
			for(xPos = pos; xPos < fmt.length(); xPos++)
				if(!Character.isDigit(fmt.charAt(xPos)))
					break;
			if(xPos > pos && xPos < fmt.length())
				if(fmt.charAt(xPos) == '$')
				{
					positionalFieldWidth = true;
					argumentPositionForFieldWidth = Integer.parseInt(fmt.substring(pos, xPos));
					pos = xPos + 1;
					ret = true;
				}
			return ret;
		}

		/**
		 * Store the digits <code>n</code> in *n$ forms.
		 */
		private boolean setPrecisionArgPosition()
		{
			boolean ret = false;
			int xPos;
			for(xPos = pos; xPos < fmt.length(); xPos++)
				if(!Character.isDigit(fmt.charAt(xPos)))
					break;
			if(xPos > pos && xPos < fmt.length())
				if(fmt.charAt(xPos) == '$')
				{
					positionalPrecision = true;
					argumentPositionForPrecision = Integer.parseInt(fmt.substring(pos, xPos));
					pos = xPos + 1;
					ret = true;
				}
			return ret;
		}

		boolean isPositionalSpecification()
		{
			return positionalSpecification;
		}

		int getArgumentPosition()
		{
			return argumentPosition;
		}

		boolean isPositionalFieldWidth()
		{
			return positionalFieldWidth;
		}

		int getArgumentPositionForFieldWidth()
		{
			return argumentPositionForFieldWidth;
		}

		boolean isPositionalPrecision()
		{
			return positionalPrecision;
		}

		int getArgumentPositionForPrecision()
		{
			return argumentPositionForPrecision;
		}

		/**
		 * Set flag characters, one of '-+#0 or a space.
		 */
		private void setFlagCharacters()
		{
			/* '-+ #0 */
			thousands = false;
			leftJustify = false;
			leadingSign = false;
			leadingSpace = false;
			alternateForm = false;
			leadingZeros = false;
			for(; pos < fmt.length(); pos++)
			{
				char c = fmt.charAt(pos);
				if(c == '\'')
					thousands = true;
				else if(c == '-')
				{
					leftJustify = true;
					leadingZeros = false;
				}
				else if(c == '+')
				{
					leadingSign = true;
					leadingSpace = false;
				}
				else if(c == ' ')
				{
					if(!leadingSign)
						leadingSpace = true;
				}
				else if(c == '#')
					alternateForm = true;
				else if(c == '0')
				{
					if(!leftJustify)
						leadingZeros = true;
				}
				else
					break;
			}
		}

		/**
		 * The integer portion of the result of a decimal conversion (i, d, u, f, g, or G) will be formatted with thousands' grouping characters. For other
		 * conversions the flag is ignored.
		 */
		private boolean thousands = false;
		/**
		 * The result of the conversion will be left-justified within the field.
		 */
		private boolean leftJustify = false;
		/**
		 * The result of a signed conversion will always begin with a sign (+ or -).
		 */
		private boolean leadingSign = false;
		/**
		 * Flag indicating that left padding with spaces is specified.
		 */
		private boolean leadingSpace = false;
		/**
		 * For an o conversion, increase the precision to force the first digit of the result to be a zero. For x (or X) conversions, a non-zero result will have 0x
		 * (or 0X) prepended to it. For e, E, f, g, or G conversions, the result will always contain a radix character, even if no digits follow the point. For g
		 * and G conversions, trailing zeros will not be removed from the result.
		 */
		private boolean alternateForm = false;
		/**
		 * Flag indicating that left padding with zeroes is specified.
		 */
		private boolean leadingZeros = false;
		/**
		 * Flag indicating that the field width is *.
		 */
		private boolean variableFieldWidth = false;
		/**
		 * If the converted value has fewer bytes than the field width, it will be padded with spaces or zeroes.
		 */
		private int fieldWidth = 0;
		/**
		 * Flag indicating whether or not the field width has been set.
		 */
		private boolean fieldWidthSet = false;
		/**
		 * The minimum number of digits to appear for the d, i, o, u, x, or X conversions. The number of digits to appear after the radix character for the e, E,
		 * and f conversions. The maximum number of significant digits for the g and G conversions. The maximum number of bytes to be printed from a string in s and
		 * S conversions.
		 */
		private int precision = 0;
		/** Default precision. */
		private final static int defaultDigits = 6;
		/**
		 * Flag indicating that the precision is *.
		 */
		private boolean variablePrecision = false;
		/**
		 * Flag indicating whether or not the precision has been set.
		 */
		private boolean precisionSet = false;
		/*
		 */
		private boolean positionalSpecification = false;
		private int argumentPosition = 0;
		private boolean positionalFieldWidth = false;
		private int argumentPositionForFieldWidth = 0;
		private boolean positionalPrecision = false;
		private int argumentPositionForPrecision = 0;
		/**
		 * Flag specifying that a following d, i, o, u, x, or X conversion character applies to a type short int.
		 */
		private boolean optionalh = false;
		/**
		 * Flag specifying that a following d, i, o, u, x, or X conversion character applies to a type lont int argument.
		 */
		private boolean optionall = false;
		/**
		 * Flag specifying that a following e, E, f, g, or G conversion character applies to a type double argument. This is a noop in Java.
		 */
		private boolean optionalL = false;
		/** Control string type. */
		private char conversionCharacter = '\0';
		/**
		 * Position within the control string. Used by the constructor.
		 */
		private int pos = 0;
		/** Literal or control format string. */
		private String fmt;
	}

	/** Vector of control strings and format literals. */
	private Vector<ConversionSpecification> vFmt = new Vector<ConversionSpecification>();
	/** Character position. Used by the constructor. */
	private int cPos = 0;
	/** Character position. Used by the constructor. */
	private DecimalFormatSymbols dfs = null;
}
